﻿using System;
using System.Collections.Generic;
using SlimDX;
using Editor.Rendering;
using Editor.Mesh;

namespace Editor
{
    internal partial class EditorDocument
    {
        #region Members
        private Command.Manager m_CommandManager = new Command.Manager();
        private String m_SceneFileName;
        private String m_SceneName;

        private List<MeshData> m_Meshes = new List<MeshData>();
        private List<Shader> m_Shaders = new List<Shader>();
        private List<Material> m_Materials = new List<Material>();
        private List<Entity> m_Entities = new List<Entity>();

        private SlimDX.Vector3 m_Position = Vector3.Zero;
        #endregion

        #region Properties
        internal Command.Manager CommandManager
        {
            get { return m_CommandManager; }
            set { m_CommandManager = value; }
        }

        public String SceneFileName
        {
            get { return m_SceneFileName; }
        }

        public String SceneName
        {
            get { return m_SceneName; }
        }

        public List<Entity> Entities
        {
            get { return m_Entities; }
        }
        #endregion

        public EditorDocument(String sceneFileName)
        {
            if (!String.IsNullOrEmpty(sceneFileName))
            {
                m_SceneFileName = sceneFileName;
                m_SceneName = System.IO.Path.GetFileNameWithoutExtension(sceneFileName);

                LoadScene(sceneFileName);
            }
        }

        public bool Save(String sceneFileName)
        {
            if (!String.IsNullOrEmpty(sceneFileName) && !System.IO.Path.Equals(sceneFileName, m_SceneFileName))
            {
                // Save with a new name (or for the first time)
                m_SceneFileName = sceneFileName;
                m_SceneName = System.IO.Path.GetFileNameWithoutExtension(sceneFileName);
            }
            else if (String.IsNullOrEmpty(sceneFileName) && !String.IsNullOrEmpty(m_SceneFileName))
            {
                // Save with the current name
            }
            else
            {
                return false;
            }

            return SaveScene(sceneFileName);
        }

        public void Update(float elapsedTime)
        {
            // Update Physics
            PhysicsUtils.PhysXScene.Simulate(elapsedTime);
            PhysicsUtils.PhysXScene.FlushStream();
            PhysicsUtils.PhysXScene.FetchResults(StillDesign.PhysX.SimulationStatus.RigidBodyFinished, true);
        }

        public Command.MoveEntitiesCommand MoveEntity(Entity entity, float deltaX, float deltaY, float deltaZ, Matrix matView)
        {
            List<Entity> entities = new List<Entity>();
            entities.Add(entity);
            return MoveEntities(entities, deltaX, deltaY, deltaZ, matView);
        }

        public Command.MoveEntitiesCommand MoveEntities(List<Entity> entities, float deltaX, float deltaY, float deltaZ, Matrix matView)
        {
            Vector3 xAxis = new Vector3(matView.M11, matView.M12, matView.M13);
            Vector3 yAxis = new Vector3(matView.M21, matView.M22, matView.M23);
            Vector3 zAxis = new Vector3(matView.M31, matView.M32, matView.M33);

            Vector3 offset = (deltaX * xAxis) + (deltaY * yAxis) + (deltaZ * zAxis);

            return new Command.MoveEntitiesCommand(entities, offset);
        }

        public Command.RotateEntitiesCommand RotateEntity(Entity entity, float deltaX, float deltaY, float deltaZ, Matrix matView)
        {
            List<Entity> entities = new List<Entity>();
            entities.Add(entity);
            return RotateEntities(entities, deltaX, deltaY, deltaZ, matView);
        }

        public Command.RotateEntitiesCommand RotateEntities(List<Entity> entities, float deltaX, float deltaY, float deltaZ, Matrix matView)
        {
            Quaternion rotAdj;
            if (Properties.Settings.Default.ZAxisUp)
                rotAdj = Quaternion.RotationYawPitchRoll(deltaX, deltaY, 0.0f);
            else
                rotAdj = Quaternion.RotationYawPitchRoll(deltaX, 0.0f, deltaY);

            Quaternion viewRot = Quaternion.RotationMatrix(matView);
            Quaternion invViewRot = Quaternion.Invert(viewRot);
            Quaternion rot = Quaternion.Multiply(invViewRot, Quaternion.Multiply(rotAdj, viewRot));

            return new Command.RotateEntitiesCommand(entities, rot);
        }

        private Material FindMaterial(Rendering.Shader shader, String textureFileName)
        {
            foreach (Material material in m_Materials)
            {
                if ((material.Shader.ShaderFileName == shader.ShaderFileName) &&
                    (material.TextureFileName == textureFileName))
                {
                    return material;
                }
            }
            return null;
        }

        private Rendering.Shader FindShader(String shaderFileName)
        {
            foreach (Rendering.Shader shader in m_Shaders)
            {
                if (shader.ShaderFileName == shaderFileName)
                {
                    return shader;
                }
            }
            return null;
        }

        private MeshData FindMesh(String fileName)
        {
            foreach (MeshData mesh in m_Meshes)
            {
                if (mesh.MeshFileName == fileName)
                    return mesh;
            }
            return null;
        }
    }
}
